package cn.stylefeng.guns.modular.demo.service;

import cn.stylefeng.guns.core.exception.BusinessException;
import cn.stylefeng.guns.core.exception.BusinessExceptionEnum;
import cn.stylefeng.guns.dao.ISaleStockService;
import cn.stylefeng.guns.dao.entity.AuditLog;
import cn.stylefeng.guns.dao.entity.AuditLogSaleStockRelation;
import cn.stylefeng.guns.dao.entity.AuditNode;
import cn.stylefeng.guns.dao.entity.SaleStock;
import cn.stylefeng.guns.dao.mapper.SaleStockMapper;
import cn.stylefeng.guns.dao.service.IAuditLogSaleStockRelationService;
import cn.stylefeng.guns.dao.service.IAuditLogService;
import cn.stylefeng.guns.dao.service.IAuditNodeService;
import cn.stylefeng.guns.modular.demo.controller.domain.*;
import cn.stylefeng.guns.modular.demo.enums.AuditStatusEnum;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.basic.SimpleRoleInfo;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.system.modular.user.entity.SysUser;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AuditLogBizService {
    @Resource
    private IAuditNodeService auditNodeService;
    @Resource
    private IAuditLogService auditLogService;
    @Resource
    private IAuditLogSaleStockRelationService auditLogSaleStockRelationService;
    @Resource
    private ISaleStockService saleStockService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SaleStockMapper saleStockMapper;


    @Transactional(rollbackFor = Exception.class)
    public void saveAuditLog(SaveAuditLogRequest saveAuditLogRequest) {
        String auditName = saveAuditLogRequest.getAuditName();
        ReportVO reportVO = saveAuditLogRequest.getReportVO();
        List<String> saleIdList = saveAuditLogRequest.getSaleIdList();
//        List<String> saleIdList = saveAuditLogRequest.getReportVO().getGoodsReportList().stream().flatMap(r -> r.getSaleStockIdList().stream()).filter(StringUtils::isNotEmpty).collect(Collectors.toList());

        AuditLog auditLog = new AuditLog();
        auditLog.setAuditName(auditName);
        auditLog.setCurrentNode(0);
        auditLog.setAuditInfo(JSON.toJSONString(reportVO));
        List<String> invoicePicList = saveAuditLogRequest.getInvoicePicList();
        if (CollectionUtils.isNotEmpty(invoicePicList)) {
            auditLog.setInvoicePic(String.join(",", invoicePicList));
        }

        int status = AuditStatusEnum.ing.getStatus();
        auditLog.setStatus(status);

        auditLogService.save(auditLog);

        List<AuditLogSaleStockRelation> collect = saleIdList.stream().map(r -> {
            AuditLogSaleStockRelation auditLogSaleStockRelation = new AuditLogSaleStockRelation();
            auditLogSaleStockRelation.setAuditLogId(auditLog.getAuditLogId());
            auditLogSaleStockRelation.setSaleStockId(r);
            auditLogSaleStockRelation.setStatus(status);
            return auditLogSaleStockRelation;
        }).collect(Collectors.toList());
        auditLogSaleStockRelationService.saveBatch(collect);

        saleStockMapper.updateStatusByIdList(status, auditLog.getAuditLogId(), saleIdList);
    }

    public PageResult<AuditLogVO> getPage(AuditQueryRequest auditQueryRequest) {
        LoginUser loginUser = LoginContext.me().getLoginUser();
        Long userId = loginUser.getUserId();
//        LoginUser loginUser = new LoginUser();
//        Long userId = 1751812971004448770L;
//        loginUser.setUserId(userId);
        Integer type = auditQueryRequest.getType();
        Page<AuditLog> page = new Page<>();
        page.setCurrent(auditQueryRequest.getPageNo());
        page.setSize(auditQueryRequest.getPageSize());
        LambdaQueryWrapper<AuditLog> auditLogLambdaQueryWrapper = Wrappers.<AuditLog>lambdaQuery();
        //待我审批的
        if (Objects.equals(type, 1)) {
            List<SimpleRoleInfo> simpleRoleInfoList = loginUser.getSimpleRoleInfoList();
            //当前有权限的节点列表
            LambdaQueryWrapper<AuditNode> cav = null;
            if (CollectionUtils.isNotEmpty(simpleRoleInfoList)) {
                List<Long> roleIdList = simpleRoleInfoList.stream().map(SimpleRoleInfo::getRoleId).collect(Collectors.toList());
                cav = Wrappers.<AuditNode>lambdaQuery().eq(AuditNode::getTemplate, "CAV").and(r -> r.eq(AuditNode::getApproverId, userId).or().in(AuditNode::getApproverId, roleIdList));
            } else {
                cav = Wrappers.<AuditNode>lambdaQuery().eq(AuditNode::getTemplate, "CAV").eq(AuditNode::getApproverId, userId);
            }


            List<AuditNode> auditNodeList = auditNodeService.list(cav);
            if (CollectionUtils.isEmpty(auditNodeList)) {
                return new PageResult();
            }
            List<Integer> nodeNOList = auditNodeList.stream().map(AuditNode::getNodeOrder).collect(Collectors.toList());
            auditLogLambdaQueryWrapper.in(AuditLog::getCurrentNode, nodeNOList);
        } else if (Objects.equals(type, 0)) {//我提交的
            auditLogLambdaQueryWrapper.eq(AuditLog::getCreateUser, userId);
        } else {
            return new PageResult();
        }
        //查询条件
        page = auditLogService.page(page, Wrappers.<AuditLog>lambdaQuery().eq(Objects.nonNull(auditQueryRequest.getAuditStatus()), AuditLog::getStatus, auditQueryRequest.getAuditStatus()).like(StringUtils.isNotBlank(auditQueryRequest.getName()), AuditLog::getAuditName, auditQueryRequest.getName())
                .orderByDesc(AuditLog::getCreateTime));
        if (page.getTotal() == 0) {
            return new PageResult();
        }
        List<AuditLog> records = page.getRecords();
        List<Long> userIdList = records.stream().flatMap(r -> Lists.newArrayList(r.getCreateUser(), r.getNode1Approver(), r.getNode2Approver(), r.getNode3Approver(), r.getNode4Approver(), r.getNode5Approver()).stream().filter(Objects::nonNull)).collect(Collectors.toList());
        Map<Long, SysUser> userMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(userIdList)) {
            List<SysUser> sysUsers = sysUserService.listByIds(userIdList);
            userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
        }
        Map<Long, SysUser> finalUserMap = userMap;
        List<AuditLogVO> collect = records.stream().map(r -> do2vo(r, finalUserMap)).collect(Collectors.toList());

        return PageResultFactory.createPageResult(collect, page.getTotal(), (int) page.getSize(), (int) page.getCurrent());
    }


    public AuditLogVO getDetail(String auditLogId) {
        AuditLog auditLog = auditLogService.getById(auditLogId);
        List<Long> userIdList = Lists.newArrayList(auditLog.getCreateUser(), auditLog.getNode1Approver(), auditLog.getNode2Approver(), auditLog.getNode3Approver(), auditLog.getNode4Approver(), auditLog.getNode5Approver()).stream().filter(Objects::nonNull).collect(Collectors.toList());
        Map<Long, SysUser> userMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(userIdList)) {
            List<SysUser> sysUsers = sysUserService.listByIds(userIdList);
            userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
        }
        Map<Long, SysUser> finalUserMap = userMap;
        return do2vo(auditLog, finalUserMap);
    }

    private AuditLogVO do2vo(AuditLog auditLog, Map<Long, SysUser> userMap) {
        if (auditLog == null) {
            return null;
        }
        AuditLogVO auditLogVO = new AuditLogVO();
        auditLogVO.setAuditLogId(auditLog.getAuditLogId());
        auditLogVO.setAuditName(auditLog.getAuditName());
        auditLogVO.setNode1ApproverUser(userMap.get(auditLog.getNode1Approver()));
        auditLogVO.setNode1ApproverPic(auditLog.getNode1ApproverPic());
        auditLogVO.setNode1Memo(auditLog.getNode1Memo());
        auditLogVO.setNode1Status(auditLog.getNode1Status());
        auditLogVO.setNode2ApproverUser(userMap.get(auditLog.getNode2Approver()));
        auditLogVO.setNode2ApproverPic(auditLog.getNode2ApproverPic());
        auditLogVO.setNode2Memo(auditLog.getNode2Memo());
        auditLogVO.setNode2Status(auditLog.getNode2Status());
        auditLogVO.setNode3ApproverUser(userMap.get(auditLog.getNode3Approver()));
        auditLogVO.setNode3ApproverPic(auditLog.getNode3ApproverPic());
        auditLogVO.setNode3Memo(auditLog.getNode3Memo());
        auditLogVO.setNode3Status(auditLog.getNode3Status());
        auditLogVO.setNode4ApproverUser(userMap.get(auditLog.getNode4Approver()));
        auditLogVO.setNode4ApproverPic(auditLog.getNode4ApproverPic());
        auditLogVO.setNode4Memo(auditLog.getNode4Memo());
        auditLogVO.setNode4Status(auditLog.getNode4Status());
        auditLogVO.setNode5ApproverUser(userMap.get(auditLog.getNode5Approver()));
        auditLogVO.setNode5ApproverPic(auditLog.getNode5ApproverPic());
        auditLogVO.setNode5Memo(auditLog.getNode5Memo());
        auditLogVO.setNode1ApproverTime(auditLog.getNode1ApproverTime());
        auditLogVO.setNode2ApproverTime(auditLog.getNode2ApproverTime());
        auditLogVO.setNode3ApproverTime(auditLog.getNode3ApproverTime());
        auditLogVO.setNode4ApproverTime(auditLog.getNode4ApproverTime());
        auditLogVO.setNode5ApproverTime(auditLog.getNode5ApproverTime());
        auditLogVO.setNode5Status(auditLog.getNode5Status());
        auditLogVO.setStatus(auditLog.getStatus());
        auditLogVO.setCurrentNode(auditLog.getCurrentNode());
        String auditInfo = auditLog.getAuditInfo();
        String invoicePic = auditLog.getInvoicePic();
        auditLogVO.setCreateSysUser(userMap.get(auditLog.getCreateUser()));
        if (StringUtils.isNotEmpty(invoicePic)) {
            auditLogVO.setInvoicePicList(List.of(invoicePic.split(",")));
        }
        if (StringUtils.isNotBlank(auditInfo)) {
            auditLogVO.setAuditInfo(JSON.parseObject(auditInfo, ReportVO.class));

        }
        return auditLogVO;
    }


    @Transactional(rollbackFor = Exception.class)
    public void audit(AuditRequest auditRequest) {
        String auditLogId = auditRequest.getAuditLogId();
        AuditLog auditLog = auditLogService.getById(auditLogId);
        Integer status = auditLog.getStatus();
        if (Objects.equals(AuditStatusEnum.pass.getStatus(), status) || Objects.equals(AuditStatusEnum.reject.getStatus(), status)) {
            throw new BusinessException(BusinessExceptionEnum.BUSINESS_PUBLIC, "已审批通过，不能再审批");
        }

        Integer currentNode = auditLog.getCurrentNode();
        List<AuditNode> auditNodes = auditNodeService.list(Wrappers.<AuditNode>lambdaQuery().eq(AuditNode::getTemplate, "CAV").eq(AuditNode::getNodeOrder, currentNode + 1));
        //流程结束了
        if (CollectionUtils.isEmpty(auditNodes)) {
            auditLog.setStatus(auditRequest.getNodeStatus());
            // 批量更新进销存关联数据
            List<AuditLogSaleStockRelation> list = auditLogSaleStockRelationService.list(Wrappers.<AuditLogSaleStockRelation>lambdaQuery().eq(AuditLogSaleStockRelation::getAuditLogId, auditLog.getAuditLogId()));
            list.forEach(r -> {
                r.setStatus(auditRequest.getNodeStatus());
            });
            List<String> saleStockIdList = list.stream().map(AuditLogSaleStockRelation::getSaleStockId).collect(Collectors.toList());
            auditLogSaleStockRelationService.updateBatchById(list);
//            List<SaleStock> saleStocks = saleStockService.listByIds(saleStockIdList);
//            saleStocks.forEach(r -> {
//                r.setAuditLogId(auditLogId);
//                r.setAuditStatus(auditRequest.getNodeStatus());
//            });
//            saleStockService.updateBatchById(saleStocks);
            saleStockMapper.updateStatusByIdList(auditRequest.getNodeStatus(), auditLog.getAuditLogId(), saleStockIdList);
        }
        fillCurrentNode(auditRequest, auditLog, currentNode);
        auditLog.setCurrentNode(auditLog.getCurrentNode() + 1);
        auditLogService.updateById(auditLog);

    }


    private void fillCurrentNode(AuditRequest auditRequest, AuditLog auditLog, Integer currentNode) {
//        LoginUser loginUser = LoginContext.me().getLoginUser();
//        Long userId = loginUser.getUserId();
//        LoginUser loginUser = new LoginUser();
        Long userId = 1751812971004448770L;
//        loginUser.setUserId(userId);
        if (currentNode == 0) {
            auditLog.setNode1Approver(userId);
            auditLog.setNode1Memo(auditRequest.getNodeMemo());
            auditLog.setNode1Status(auditRequest.getNodeStatus());
            auditLog.setNode1ApproverPic(auditRequest.getNodeApproverPic());
            auditLog.setNode1ApproverTime(System.currentTimeMillis());
        } else if (currentNode == 1) {
            auditLog.setNode2Approver(userId);
            auditLog.setNode2Memo(auditRequest.getNodeMemo());
            auditLog.setNode2Status(auditRequest.getNodeStatus());
            auditLog.setNode2ApproverPic(auditRequest.getNodeApproverPic());
            auditLog.setNode2ApproverTime(System.currentTimeMillis());
        } else if (currentNode == 2) {
            auditLog.setNode3Approver(userId);
            auditLog.setNode3Memo(auditRequest.getNodeMemo());
            auditLog.setNode3Status(auditRequest.getNodeStatus());
            auditLog.setNode3ApproverPic(auditRequest.getNodeApproverPic());
            auditLog.setNode3ApproverTime(System.currentTimeMillis());
        } else if (currentNode == 3) {
            auditLog.setNode4Approver(userId);
            auditLog.setNode4Memo(auditRequest.getNodeMemo());
            auditLog.setNode4Status(auditRequest.getNodeStatus());
            auditLog.setNode4ApproverPic(auditRequest.getNodeApproverPic());
            auditLog.setNode4ApproverTime(System.currentTimeMillis());
        } else if (currentNode == 4) {
            auditLog.setNode5Approver(userId);
            auditLog.setNode5Memo(auditRequest.getNodeMemo());
            auditLog.setNode5Status(auditRequest.getNodeStatus());
            auditLog.setNode5ApproverPic(auditRequest.getNodeApproverPic());
            auditLog.setNode5ApproverTime(System.currentTimeMillis());
        }

    }

}
